﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MinerManager.Common
{
	/// <summary>
	/// 提供连接NodeServer服务的方法。
	/// </summary>
	public class ConnectionServer
	{
		#region private string GetNodeServerUrl 获取NodeServerList的Url。

		private string GetNodeServerUrl
		{
			get
			{
				string url = System.Configuration.ConfigurationManager.AppSettings["NodeServerList"];
				if (string.IsNullOrWhiteSpace(url))
					throw new NullReferenceException("缺少NodeServerList配置。");

				return url;
			}
		}

		#endregion

		private Common.AgentComponent Agent = null;
		private List<Models.NodeServer> NodeServer = new List<Models.NodeServer>();//本地存储的NodeServer信息集合

		/// <summary>
		/// 当前登录NodeServer的IP地址。
		/// </summary>
		public string CurrentNodeServerIP = string.Empty;

		/// <summary>
		/// 当前登录NodeServer的端口号。
		/// </summary>
		public ushort CurrentNodeServerPort = 0;

		#region ConnectionServer(Common.AgentComponent agent) 初始化 ConnectionServer 的实例。

		/// <summary>
		/// 初始化 <see cref="ConnectionServer"/> 的实例。
		/// </summary>
		/// <param name="agent"></param>
		public ConnectionServer(Common.AgentComponent agent)
		{
			if (agent == null)
				throw new ArgumentNullException("agent is null");

			this.Agent = agent;
			this.NodeServer = GetLocalNodeServerList();
		}

		#endregion

		#region bool Connection() 执行NodeServer连接操作。

		/// <summary>
		/// 执行NodeServer连接操作。
		/// </summary>
		/// <returns>是否连接成功</returns>
		public bool Connection()
		{
			bool result = false;

			//检测最后一次连接NodeServer信息
			int index = this.NodeServer.FindIndex(p => p.IsLastConnectionSuccess);//本地NodeServer列表中，最后一次成功连接NodeServer的信息索引号
			if (index >= 0)
			{
				//执行连接操作
				bool isStarted = Connection(this.NodeServer[index].IP, this.NodeServer[index].Port);
				if (isStarted)
				{
					this.CurrentNodeServerIP = this.NodeServer[index].IP;
					this.CurrentNodeServerPort = this.NodeServer[index].Port;
					result = true;
				}
				else
				{
					this.NodeServer[index].IsLastConnectionSuccess = false;

					//Http请求NodeServer列表
					this.NodeServer = GetHttpNodeServerList();
					for(int i = 0; i < this.NodeServer.Count; i++)
					{
						isStarted = Connection(this.NodeServer[i].IP, this.NodeServer[i].Port);
						if (isStarted)
						{
							this.CurrentNodeServerIP = this.NodeServer[i].IP;
							this.CurrentNodeServerPort = this.NodeServer[i].Port;
							this.NodeServer[i].IsLastConnectionSuccess = true;
							result = true;
							break;
						}
					}
					SaveNodeServerList(this.NodeServer);
				}
			}
			else
			{
				//循环连接本地存储的NodeServer信息
				bool isStartedByLocal = false;
				for (int i = 0; i < this.NodeServer.Count; i++)
				{
					//执行连接操作
					isStartedByLocal = Connection(this.NodeServer[i].IP, this.NodeServer[i].Port);
					if (isStartedByLocal)
					{
						this.CurrentNodeServerIP = this.NodeServer[i].IP;
						this.CurrentNodeServerPort = this.NodeServer[i].Port;
						this.NodeServer[i].IsLastConnectionSuccess = true;
						result = true;
						break;
					}
				}

				//本地存储的NodeServer未成功连接时执行
				if (!isStartedByLocal)
				{
					//Http请求NodeServer列表
					this.NodeServer = GetHttpNodeServerList();
					for (int i = 0; i < this.NodeServer.Count; i++)
					{
						//执行连接操作
						bool isStarted = Connection(this.NodeServer[i].IP, this.NodeServer[i].Port);
						if (isStarted)
						{
							this.CurrentNodeServerIP = this.NodeServer[i].IP;
							this.CurrentNodeServerPort = this.NodeServer[i].Port;
							this.NodeServer[i].IsLastConnectionSuccess = true;
							result = true;
							break;
						}
					}
					SaveNodeServerList(this.NodeServer);
				}
			}
			return result;
		}

		#endregion

		#region bool Connection(string ip, ushort port) 使用指定IP和端口号连接NodeServer。

		/// <summary>
		/// 使用指定IP和端口号连接NodeServer。
		/// </summary>
		/// <param name="ip">IP地址</param>
		/// <param name="port">端口号</param>
		/// <returns>是否连接成功</returns>
		public bool Connection(string ip, ushort port)
		{
			if (this.Agent.IsStarted)
				this.Agent.Stop();

			if (!this.Agent.ExceptionClose)
			{
				this.Agent.LocalIp = MyIp();
				this.Agent.ServerIp = ip;
				this.Agent.ServerPort = port;
				this.Agent.Start();
			}
			else
			{
				this.Agent.AgentConnServer();
			}

			return this.Agent.IsStarted;
		}

		#endregion

		#region private void SaveNodeServerList(List<Models.NodeServer> infos) 保存NodeServer信息集合到本地。

		/// <summary>
		/// 保存NodeServer信息集合到本地。
		/// </summary>
		/// <param name="infos"></param>
		private void SaveNodeServerList(List<Models.NodeServer> infos)
		{
			string path = System.IO.Path.Combine(Environment.CurrentDirectory, "ServerIps.txt");
			string str = TomNet.Utility.Data.JsonHelper.ToJson(infos);
			System.IO.File.WriteAllText(path, str);
		}

		#endregion

		#region private List<Models.NodeServer> GetLocalNodeServerList() 获取本地NodeServer信息集合。

		/// <summary>
		/// 获取本地NodeServer信息集合。
		/// </summary>
		/// <returns></returns>
		private List<Models.NodeServer> GetLocalNodeServerList()
		{
			List<Models.NodeServer> result = new List<Models.NodeServer>();

			string path = System.IO.Path.Combine(Environment.CurrentDirectory, "ServerIps.txt");
			if (System.IO.File.Exists(path))
			{
				try
				{
					string str = System.IO.File.ReadAllText(path, Encoding.UTF8);
					result = TomNet.Utility.Data.JsonHelper.FromJson<List<Models.NodeServer>>(str);
				}
				catch { }
			}

			return result;
		}

		#endregion

		#region private List<Models.NodeServer> GetHttpNodeServerList() 请求Http获取NodeServer信息集合。

		/// <summary>
		/// 请求Http获取NodeServer信息集合。
		/// </summary>
		/// <returns></returns>
		private List<Models.NodeServer> GetHttpNodeServerList()
		{
			List<Models.NodeServer> result = new List<Models.NodeServer>();

			string str = Get(this.GetNodeServerUrl, Encoding.UTF8);
			if (!string.IsNullOrWhiteSpace(str))
			{
				try
				{
					Models.HttpNodeServer info = TomNet.Utility.Data.JsonHelper.FromJson<Models.HttpNodeServer>(str);
					foreach(string ipStr in info.NodeSvr)
					{
						string ip = ipStr.Split(':')[0];
						ushort port = Convert.ToUInt16(ipStr.Split(':')[1]);
						result.Add(new Models.NodeServer
						{
							IP = ip,
							Port = port,
							IsLastConnectionSuccess = false
						});
					}
				}
				catch { }
			}

			return result;
		}

		#endregion

		#region private static string Get(string url, Encoding enCoding, string userAgent = "") Get方式获取数据。

		/// <summary>
		/// Get方式获取数据。
		/// </summary>
		/// <param name="url">连接地址</param>
		/// <param name="enCoding">字符编码</param>
		/// <param name="userAgent">User-agentHTTP 标头的值</param>
		/// <returns></returns>
		private static string Get(string url, Encoding enCoding, string userAgent = "")
		{
			string result = string.Empty;

			try
			{
				global::System.Net.HttpWebRequest request = (global::System.Net.HttpWebRequest)global::System.Net.WebRequest.Create(url);
				request.UserAgent = userAgent;
				request.Credentials = global::System.Net.CredentialCache.DefaultCredentials;
				global::System.Net.WebResponse response = request.GetResponse();
				using (global::System.IO.Stream readStream = response.GetResponseStream())
				{
					global::System.IO.StreamReader reader = new global::System.IO.StreamReader(readStream, enCoding);
					result = reader.ReadToEnd();
					reader.Close();
					reader.Dispose();
				}
				response.Close();
			}
			catch { }

			return result;
		}

		#endregion

		#region string MyIp()

		private string MyIp()
		{
			string result = string.Empty;

			string name = System.Net.Dns.GetHostName();
			System.Net.IPAddress[] ipadrlist = System.Net.Dns.GetHostAddresses(name);
			foreach (System.Net.IPAddress ipa in ipadrlist)
			{
				if (ipa.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
					result = ipa.ToString();
			}

			return result;
		}

		#endregion
	}
}
